package com.pan.service.impl;

import com.pan.dao.UserDao;
import com.pan.dao.UserTableSelectDao;
import com.pan.dao.UserTableUpdateDao;
import com.pan.entity.Result;
import com.pan.entity.User;
import com.pan.enume.ResultEnum;
import com.pan.service.UserService;
import com.pan.tools.*;
import com.pan.vo.UserRegisterVo;
import com.pan.vo.UserVo;
import com.pan.vo.utils.ConvertObject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;


@Service("userService")
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDao;

    @Resource
    private UserTableSelectDao userTableSelectDao;

    @Resource
    private UserTableUpdateDao userTableUpdateDao;
    @Resource
    private RedisTools redisTools;

    @Override
    public Result toLogin(HttpServletRequest request, HttpServletResponse response, Long tel, String password){
        Result<String> loginResult = login(tel,password);
        if (loginResult.getCode()!=200){
            return loginResult;
        }
        Cookie cookie = CookieTools.getCookie(request,"userTicket",loginResult.getData());
        response.addCookie(cookie);
        return new Result(ResultEnum.SUCCESS,loginResult.getData());
    }


    @Transactional
    public Result<String> login(Long tel, String password) {
        User user = userTableSelectDao.selectByTel(tel);
        if (user == null){
            return new Result(ResultEnum.USER_NOT_FOUND_ERROR);
        }
        String salt = user.getSalt();
        String passwordAddSalt = MD5Tools.fromPassToDBPass(password,salt);
        if (!passwordAddSalt.equals(user.getPassword())){
            return new Result(ResultEnum.PASSWORD_ERROR);
        }

        Long loginCount = user.getLoginCount()+1;
        Timestamp nowTime = new Timestamp(System.currentTimeMillis());
        userTableUpdateDao.updateLoginCount(user.getId(),loginCount);
        userTableUpdateDao.updateLastLoginDate(user.getId(),nowTime);
        user.setLastLoginDate(nowTime).setLoginCount(loginCount);

        String userTicket = UUIDTools.getUUID();
        Map map = ObjectToMap.toMap(user);
        redisTools.hset("user:"+userTicket,map);
        redisTools.expire("user:"+userTicket,7L);

        return new Result(ResultEnum.SUCCESS,userTicket);
    }

    @Override
    @Transactional
    public Result register(UserRegisterVo userRegisterVo) {

        User isUser = userTableSelectDao.selectByTel(userRegisterVo.getTel());
        if (isUser != null ){
            return new Result(403,"该账户已经存在");
        }

        String salt = SaltTools.getSalt(6);
        String passwordAddSalt = MD5Tools.fromPassToDBPass(userRegisterVo.getPassword(),salt);
        User user = new User(userRegisterVo,passwordAddSalt,salt);

        Long id = userDao.insert(user);
        return new Result(ResultEnum.SUCCESS,id);
    }

    @Override
    public Result logoff(HttpServletResponse response,String userTicket){
        Cookie cookie = new Cookie("userTicket","");
        cookie.setPath("/");
        cookie.setMaxAge(-1);
        response.addCookie(cookie);
        redisTools.del("user:"+userTicket);

        return new Result(ResultEnum.SUCCESS);
    }

    @Override
    public  Result<UserVo> selectByTel(String userTicket, Long tel){
        Result isUser = redisTools.hget("user:"+userTicket,"id");
        Long id = (Long) isUser.getData();
        if (isUser.getCode()!=200||id==null){
            return new Result<>(ResultEnum.NOT_LOGIN_ERROR);
        }
        User user = userTableSelectDao.selectByTel(tel);
        UserVo userVo = (UserVo) ConvertObject.forceConvertObject(UserVo.class,user);
        return new Result(ResultEnum.SUCCESS,userVo);
    }

    @Override
    public Result<UserVo> selectById(Long id){
        User user = userTableSelectDao.selectById(id);
        if (user==null){
            return new Result<>(ResultEnum.USER_NOT_FOUND_ERROR);
        }
        UserVo userVo = (UserVo) ConvertObject.convertObject(UserVo.class,user);
        return new Result<>(ResultEnum.SUCCESS,userVo);
    }



    @Transactional
    @Override
    public Result updatePassword(String userTicket, String oldPassword, String newPassword) throws NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        Result idResult = redisTools.hget("user:"+userTicket,"id");
        Long id = (Long) idResult.getData();
        if (idResult.getCode()!=200||id==null){
            return new Result(ResultEnum.NOT_LOGIN_ERROR);
        }
        User user = userTableSelectDao.selectById(id);
        String oldSalt = user.getSalt();
        String oldPasswordAddSalt =  MD5Tools.fromPassToDBPass(oldPassword,oldSalt);
        if (!oldPasswordAddSalt.equals(user.getPassword())){
            return new Result(ResultEnum.PASSWORD_ERROR);
        }
        String newSalt = SaltTools.getSalt(6);
        String newPasswordAddSalt = MD5Tools.fromPassToDBPass(newPassword,newSalt);
        updateInfo(userTicket,"password",newPasswordAddSalt);
        updateInfo(userTicket,"salt",newSalt);
        Map<String,Object> map = new HashMap();
        map.put("password",newPasswordAddSalt);
        map.put("salt",newSalt);
        redisTools.hset("user:"+userTicket,map);
        return new Result(ResultEnum.SUCCESS);
    }

    @Override
    @Transactional
    public <T> Result updateInfo(String userTicket, String memberName, T value) throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Result userResult = redisTools.hget("user:"+userTicket,"id");
        Long id = Long.parseLong((String) userResult.getData());
        if (userResult.getCode()!=200||id==null){
            return new Result(ResultEnum.NOT_LOGIN_ERROR);
        }
        Field field =null;
        try {
            field = User.class.getDeclaredField(memberName);
        }catch (Exception e){
            return new Result(403,"没有该属性"+memberName,e);
        }
        Class memberType = field.getType();
        Object memberValue;
        if (memberType == Long.class){
            memberValue = Long.parseLong((String) value);
        }
        else {
            memberValue = memberType.cast(value);
        }
        String firstUp = memberName.substring(0,1).toUpperCase()+memberName.substring(1);
        String methodName = "update"+firstUp;
        Method method = UserTableUpdateDao.class.getMethod(methodName,Long.class,memberType);
        method.invoke(userTableUpdateDao,id,memberValue);
        return new Result(ResultEnum.SUCCESS);
    }

}
